

const PENDING = 'pending'
const FULFILLED = 'fulFilled'
const REJECTED = 'rejected'
/**
 * 手写MyPromise源码
 */
class MyPromise {
  constructor(fn) {
    try {
      //promise处理器,一个返回成功调用的函数，一个返回失败调用的函数
      fn(this._resolve, this._reject)
    } catch (error) {
      //捕获异常后直接调用失败回调
      this.reject(error)
    }
  }
  state = PENDING
  /**
   * 成功之后的值
   */
  value = undefined
  /**
   * 失败的原因
   */
  reason = undefined
  /**
   * 存储异步处理时多个then方法的成功回调
   */
  successCallback = []
  /**
   * 存储异步处理时多个then方法的失败回调
   */
  failCallback = []
  /**
   * 将promise状态变为FULFILLED,并通知所有的then方法的成功回调，传递resolve传递的值
   * @param value
   */
  _resolve = (value) => {
    if (this.state != PENDING) return
    this.state = FULFILLED
    this.value = value
    while (this.successCallback.length) {
      this.successCallback.shift()(this.value)
    }
  }
  /**
   * 将promise状态变为REJECTED,并通知所有的then方法的失败回调，传递reject传递的值
   * @param {*} reason
   */
  _reject = (reason) => {
    if (this.state != PENDING) return
    this.state = REJECTED
    this.reason = reason
    while (this.failCallback.length) {
      this.failCallback.shift()(this.reason)
    }
  }
  /**
   * 返回promise对象，实现链式调用，注册成功和失败的回调函数
   * @param  successCallback
   * @param  failCallback
   */
  then = (successCallback, failCallback) => {
    successCallback = successCallback ? successCallback : value => value
    failCallback = failCallback ? failCallback : reason => { throw reason }
    //实现链式调用
    let promise2 = new MyPromise((resolve, reject) => {
      if (this.state === FULFILLED) {

        //为了变成异步代码
        setTimeout(() => {
          try {
            let result = successCallback(this.value)
            resolvePromise(promise2, result, resolve, reject)
          } catch (error) {
            reject(error)
          }
          // resolve(successCallback(this.value))
        }, 0);

      } else if (this.state === REJECTED) {

        setTimeout(() => {
          try {
            let result = failCallback(this.reason)
            resolvePromise(promise2, result, resolve, reject)
          } catch (error) {
            reject(error)
          }
        }, 0);
      } else {
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              let result = successCallback(this.value)
              resolvePromise(promise2, result, resolve, reject)
            } catch (error) {
              reject(error)
            }
          }, 0);
        })
        this.failCallback.push(() => {
          setTimeout(() => {
            try {
              let result = failCallback(this.reason)
              resolvePromise(promise2, result, resolve, reject)
            } catch (error) {
              reject(error)
            }
          }, 0);
        })
        // this.successCallback.push(successCallback)
        // this.failCallback.push(failCallback)
      }
    })

    return promise2
  }

  /**
   * 注册失败回调函数,如果失败catch中的回调函数就会被调用
   * @param {}} failback
   */
  catch = (failback) => {
    return this.then(undefined,failback)
  }

  /**
   * 直接通过调用当前对象then方法，添加成功和失败的回调函数。通过myPromise的链式调用将当前promise的结果在新的执行了入参传递的回调函数后新promise对象中，如果当前时成功则返回成功的返回值，如果是失败的则通过抛出失败原因的异常传递失败原因到下一个对象的失败回调中。
   * @param callback
   */
  finally(callback){
    return this.then(value => {
      // callback()
      // return value
      return MyPromise.resolve(callback()).then(()=>value)
    },reason => {
      // callback()
      // throw reason
      return MyPromise.resolve(callback()).then((()=> {throw reason}))
    })

  }

  /**
   * 通过循环传递进来的列表，对每一项进行调用，将成功结果保存在数组中,通过计数，当得到结果的数量
   * 等于参数数组长度，则表示所有异步任务已完成，放回所有结果，如果有失败则直接返回失败。
   * @param {*} promiseList
   */
  static all(promiseList){
    let allResolve =[]
    let index = 0;
    function addDate(key,value,resolve) {
      allResolve[key] = value
      index++
      if(index === promiseList.length){
        resolve(allResolve)
      }
    }
    return new MyPromise((resolve,reject)=>{
      for (let i = 0; i < promiseList.length; i++) {
        const current = promiseList[i];
        if(current instanceof MyPromise){
          //promise对象
          current.then(value => addDate(i,value,resolve),reason => reject(reason))
        }else{
          //普通值
          addDate(i,current,resolve)
        }
      }
    })
  }

  /**
   * 返回一个状态时成功的promise对象，如果value时promise对象则返回value
   * @param {} value
   */
  static resolve(value){
    if(value instanceof MyPromise){
      return value
    }
    return new MyPromise((resolve)=>{
      return resolve(value)
    })
  }
}

/**
 * 判断then方法中会回调函数的返回值，返回结果不能是当前then返回的对象本身，如果回调函数返回结果
 * 是promise,则将对应的成功，失败的结果传递给下一个对象 。如果不是则将当前promise的回调方法的
 * 返回值传递给下一个promise的then方法的回调函数，
 * @param {*} promise2
 * @param {*} result //回调函数的返回结果
 * @param {*} resolve
 * @param {*} reject
 */
function resolvePromise(promise2, result, resolve, reject) {
  if (promise2 === result) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if (result instanceof MyPromise) {
    result.then(resolve, reject)
  } else {
    resolve(x)
  }
}
module.exports = MyPromise